package individual.ircon.bilibili.ui;

import individual.ircon.bilibili.network.DanmuMessageHandleCallback;
import individual.ircon.bilibili.network.DanmuWSSClient;
import individual.ircon.bilibili.network.HttpApiException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Alert;
import javafx.stage.WindowEvent;


import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;

import static individual.ircon.bilibili.ui.Tools.alert;
import static individual.ircon.bilibili.ui.Tools.showLotteryView;

/**
 * 弹幕抽奖的界面和界面控制。理论上，如果不对界面进行二次开发，直接调用这个就行。
 * 如果你是为了获取UI组件，直接调用getUI()即可。其他的不用管，都处理好了。
 */
public class DanmuLotteryCmd {
    private final FXMLLoader Loader;
    private final DanmuLottery Control;
    private final ObservableList<DanmuData> List;
    private DanmuWSSClient WSSClient;
    private final Parent UI;

    /**
     * 这个界面的工作状态。0没有开始监听。1开始监听。
     */
    private int WorkState = 0;

    /// =======================
    /// ====== Construct ======
    /// =======================

    /**
     * 构造器。
     */
    public DanmuLotteryCmd() throws IOException {
        Loader = DanmuLottery.getLoader();
        UI = Loader.load();
        Control = Loader.getController();
        List = FXCollections.observableArrayList();
        Control.setList(List);

        setFunction();
        flushView();

    }
    private void exitAction() { // 注意有心跳线程的存在。
        UI.getScene().getWindow().addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, event->{

            if(WSSClient != null) {
                try {
                    WSSClient.closeBlocking();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                WSSClient = null;
            }
        });
    }

    /**
     * 设置组件的功能。
     */
    private void setFunction() {
        Control.setStartCall(()->clickButton(0));
        Control.setStopCall(()->clickButton(1));
        Control.setLotteryCall(()->clickButton(2));
    }

    /**
     * 按钮的功能。
     * @param index 按钮的编号。
     */
    private void clickButton(int index) {
        /*
        0 开始按钮 1 停止 2 抽奖
         */
        switch (index){
            case 0:
                startButton();
                break;
            case 1:
                stopButton();
                break;
            case 2:
                lotteryButton();
                break;
            default:
                break;
        }
    }

    private void lotteryButton() {
        if(List.isEmpty()) { // 列表是否为空。
            alert(Alert.AlertType.WARNING, "警告", "列表为空。");
            return;
        }

        HashSet<Long> set = new HashSet<>();
        ArrayList<Shortlist> list = new ArrayList<>();

        for(var v: List) {
            long id = v.getUserID();
            if(!set.contains(id)) {
                list.add(new Shortlist(v.getUserID(), v.getUserName()));
                set.add(id);
            }
        }

        showLotteryView(list, 400, 400);
    }

    private void flushView() {
        if(WorkState == 0) { // 没有工作
            Control.setState(0);
        }else if(WorkState == 1){ // 开始工作
            Control.setState(1);
        }
    }
    /**
     * 停止按钮。
     */
    private void stopButton(){
        // 判断工作状态。
        if(WorkState == 0) { // 没再工作状态
            alert(Alert.AlertType.WARNING, "注意", "已经停止工作。");
        }else{ // 在工作状态。
            if(WSSClient != null) {
                WSSClient.close(1000, "Client want to be close.");
                WSSClient = null; // 释放对象
            }
            WorkState = 0;
            alert(Alert.AlertType.INFORMATION, "注意", "停止工作成功!");
        }
        flushView();
    }

    /**
     * 开始按钮。
     */
    private void startButton() {
        /// 已经开始工作
        if(WorkState == 1) {
            alert(Alert.AlertType.INFORMATION, "注意", "已经开始工作。");
        }else{ /// 没有工作

            /// 处理必要的数据。
            String id_str = Control.getRoomID();
            String word = Control.getKeyWord();
            final boolean pattern = Control.isAllCheck();

            // 判断内容是否为空
            if(!(
                    id_str != null && !id_str.isEmpty()
                && word != null
            )){ // 如果空
                alert(Alert.AlertType.WARNING, "注意", "房间ID为空。");
                return; // !!!!
            }

            // 把房间号转成数字。
            Long room = null;
            try{
                room = Long.valueOf(id_str);
            }catch (NumberFormatException e){
                e.printStackTrace();
            }
            if(room == null) { // 如果转化失败
                alert(Alert.AlertType.WARNING, "注意", "房间ID必须是数字。");
                return; // !!!!
            }

            // 开始初始化wss
            var builder = new DanmuWSSClient.Builder();
            try { // 获取房间的信息
                builder.setRoomUrlID(room);
            } catch (HttpApiException | URISyntaxException e) {
                e.printStackTrace();
                alert(Alert.AlertType.WARNING, "注意", "获取直播间信息失败。");
                return;
            }

            // 设置监听
            DanmuMessageHandleCallback cal = new DanmuMessageHandleCallback(
                    message -> {
                        boolean flag = false;
                        if(pattern) {
                            if(message.Danmu.equals(word)) {
                                flag = true;
                            }
                        }else{
                            if(message.Danmu.contains(word)){
                                flag = true;
                            }
                        }
                        if(flag)
                            List.add(new DanmuData(message.UserID, message.UserName, message.Danmu));
                    }
            );
            builder.setOnMessageByte(cal::handle);

            // 启动 wss
            try{
                WSSClient = builder.build();
            }catch (InterruptedException e){
                e.printStackTrace();
            }

            if(WSSClient == null) { // 启动失败
                alert(Alert.AlertType.WARNING, "注意", "WSS启动失败。");
                return;
            }

            WorkState = 1; // 设置状态为开始工作。
            alert(Alert.AlertType.INFORMATION, "注意", "启动成功！");

            exitAction(); // 保证窗口关闭的时候，wss可以正常推出。

        }
        flushView();
    }


    /// ======================
    /// ====== Function ======
    /// ======================

    /**
     * 获取fx加载器。理论上，在构造好这个对象之后你不需要再获取这个对象。
     * @return 加载器。
     */
    public FXMLLoader getLoader() {
        return Loader;
    }

    /**
     * 获取控制器。理论上控制器在构造这个对象的时候就是构造好的。
     * @return 控制器对象。
     */
    public DanmuLottery getControl() {
        return Control;
    }

    /**
     * 获取UI队对象。
     * @return UI对象。
     * @throws IOException 如果加载fx文档失败。
     */
    public Parent getUI() throws IOException {
        return UI;
    }


}
